/*
 * FilterGraph.cpp
 *
 *  Created on: 2016年1月4日
 *      Author: terry
 */

#include "FilterGraph.h"

namespace av
{

#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
#else
#define _snprintf_s snprintf
#endif //


FilterGraph::FilterGraph()
{
}

FilterGraph::~FilterGraph()
{
	close();
}

int FilterGraph::open(int width, int height, AVPixelFormat pixFmt, const std::string& filters)
{
	m_graph.reset(avfilter_graph_alloc(), AVFilterGraphDeleter());

	AVFilter* buffersrc  = avfilter_get_by_name("buffer");
	AVFilter* buffersink = avfilter_get_by_name("buffersink");

	/* buffer video source: the decoded frames from the decoder will be inserted here. add src filter */
	char args[256];
	_snprintf_s(args, sizeof(args),
		"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d",
		width, height, pixFmt,
		1, 1000);

	AVFilterContext* filt_ctx = NULL;
	int ret = avfilter_graph_create_filter(&filt_ctx, buffersrc, "in",
		args, NULL, m_graph.get());
	if (ret < 0)
	{
		close();
		return ret;
	}

	m_srcFilter.reset(filt_ctx, avfilter_free);

	/* buffer video sink: to terminate the filter chain. */
	AVBufferSinkParams* buffersink_params = av_buffersink_params_alloc();
	enum AVPixelFormat pix_fmts[] = { pixFmt, AV_PIX_FMT_NONE };
	buffersink_params->pixel_fmts = pix_fmts;
	ret = avfilter_graph_create_filter(&filt_ctx, buffersink, "out",
		NULL, buffersink_params, m_graph.get());

	av_free(buffersink_params);

	if (ret < 0)
	{
		close();
		return ret;
	}

	m_sinkFilter.reset(filt_ctx, avfilter_free);

	AVFilterInOut* filterIn = avfilter_inout_alloc();
	AVFilterInOut* filterOut = avfilter_inout_alloc();

	/* Endpoints for the filter graph. */
	filterOut->name       = av_strdup("in");
	filterOut->filter_ctx = m_srcFilter.get();
	filterOut->pad_idx    = 0;
	filterOut->next       = NULL;

	filterIn->name       = av_strdup("out");
	filterIn->filter_ctx = m_sinkFilter.get();
	filterIn->pad_idx    = 0;
	filterIn->next       = NULL;

	ret = avfilter_graph_parse_ptr(m_graph.get(), filters.c_str(), &filterIn, &filterOut, NULL);

	m_filterIn.reset(filterIn, AVFilterInOutDeleter());
	m_filterOut.reset(filterOut, AVFilterInOutDeleter());

	if (ret < 0)
	{
		close();
		return ret;
	}

	ret = avfilter_graph_config(m_graph.get(), NULL);
	if (ret < 0)
	{
		close();
		return ret;
	}

	return ret;
}

void FilterGraph::close()
{
	m_srcFilter.reset();
	m_sinkFilter.reset();

	m_filterIn.reset();
	m_filterOut.reset();

	m_graph.reset();
}

bool FilterGraph::isOpen()
{
	return (m_graph.get() != NULL);
}

int FilterGraph::filter(AVFrame* inFrame, AVFrame* outFrame)
{
	int ret = -1;
	if (m_srcFilter && m_sinkFilter)
	{
		av_buffersrc_add_frame(m_srcFilter.get(), inFrame);
		ret = av_buffersink_get_frame(m_sinkFilter.get(), outFrame);
	}
	return ret;
}



} /* namespace av */
